<template>
  <el-container>
    <el-header>
      <h2>流程图编辑</h2>
    </el-header>
    <el-main>
      <div class="content">
        <div ref="stencilContainer" class="app-stencil"/>
        <div id="x6" ref="container" class="app-content"/>
      </div>
    </el-main>
  </el-container>
</template>

<script>
import { Graph, Addon, Shape, FunctionExt } from '@antv/x6'
export default {
  data() {
    return {
      graph: '',
      stencil: '',
      grid: {
        visible: true,
        size: 10,
        type: 'doubleMesh',
        args: [
          {
            color: '#D3CFCF',
            thickness: 0.5
          },
          {
            color: '#E1E0E0',
            thickness: 2,
            factor: 5
          }
        ]
      },
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 2,
              fill: '#fff',
              style: {
                visibility: 'hidden'
              }
            }
          }
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 2,
              fill: '#fff',
              style: {
                visibility: 'hidden'
              }
            }
          }
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 2,
              fill: '#fff',
              style: {
                visibility: 'hidden'
              }
            }
          }
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 2,
              fill: '#fff',
              style: {
                visibility: 'hidden'
              }
            }
          }
        }
      },
      items: [
        {
          group: 'top'
        },
        {
          group: 'right'
        },
        {
          group: 'bottom'
        },
        {
          group: 'left'
        }
      ]
    }
  },
  methods: {
    initX6() {
      this.graph = new Graph({
        container: document.getElementById('x6'),
        grid: this.grid,
        panning: true,
        width: 500,
        height: 500,
        mousewheel: {
          enabled: true,
          modifiers: ['ctrl', 'meta'],
          minScale: 0.5,
          maxScale: 3
        },
        resizing: true,
        rotating: true,
        connecting: {
          router: 'manhattan',
          connector: {
            name: 'rounded',
            args: {
              radius: 8
            }
          },
          anchor: 'center',
          connectionPoint: 'anchor',
          allowBlank: false,
          snap: {
            radius: 20
          },
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: '#000',
                  strokeWidth: 1,
                  targetMarker: {
                    name: 'block',
                    width: 12,
                    height: 8
                  }
                }
              },
              zIndex: 0
            })
          },
          validateConnection({ targetMagnet }) {
            return !!targetMagnet
          }
        },
        selecting: {
          enabled: true,
          rubberband: true,
          modifiers: ['ctrl', 'meta'],
          showNodeSelectionBox: true
        },
        snapline: true,
        keyboard: true,
        history: true,
        clipboard: true
      })
      this.initStencil()
      this.initShape()
      this.initEvent()
      this.initKeyboard()
    },
    initStencil() {
      this.stencil = new Addon.Stencil({
        title: 'Flowchart',
        target: this.graph,
        stencilGraphWidth: 200,
        stencilGraphHeight: 450,
        layoutOptions: {
          columns: 1,
          columnWidth: 230,
          rowHeight: 80,
          marginY: 20
        }
        // getDropNode(node) {
        //   const size = node.size()
        //   return node.clone().size(size.width * 3, size.height * 3)
        // }
      })
      this.$refs.stencilContainer.appendChild(this.stencil.container)
    },
    initShape() {
      const start = new Shape.Rect({
        width: 100,
        height: 50,
        attrs: {
          text: {
            text: 'Start'
          },
          body: {
            rx: 20,
            ry: 45,
            strokeWidth: 1,
            fill: '#d9b5e7',
            stroke: '#0d0e0d',
            color: '#0d0e0d'
          },
          label: {
            fontSize: 14,
            fontWeight: 400
          }
        },
        ports: {
          groups: this.groups,
          items: this.items
        }
      })
      const end = new Shape.Rect({
        width: 100,
        height: 50,
        attrs: {
          text: {
            text: 'End'
          },
          body: {
            rx: 20,
            ry: 45,
            strokeWidth: 1,
            fill: '#d9b5e7',
            stroke: '#0d0e0d',
            color: '#0d0e0d'
          },
          label: {
            fontSize: 14,
            fontWeight: 400
          }
        },
        ports: {
          groups: this.groups,
          items: this.items
        }
      })
      const rect = new Shape.Rect({
        width: 100,
        height: 50,
        attrs: {
          body: {
            strokeWidth: 1,
            fill: '#76f16e',
            stroke: '#0d0e0d',
            color: '#0d0e0d'
          },
          label: {
            fontSize: 14,
            fontWeight: 400
          }
        },
        ports: {
          groups: this.groups,
          items: this.items
        }
      })
      const circle = new Shape.Circle({
        width: 25,
        height: 25,
        attrs: {
          body: {
            strokeWidth: 1,
            fill: '#76f16e',
            stroke: '#0d0e0d',
            color: '#0d0e0d'
          },
          label: {
            fontSize: 14,
            fontWeight: 400
          }
        },
        ports: {
          groups: this.groups,
          items: this.items
        }
      })
      const prismatic = new Shape.Polygon({
        width: 100,
        height: 50,
        attrs: {
          body: {
            strokeWidth: 1,
            refPoints: '0,20 40,40 80,20 40,0',
            fill: '#76f16e',
            stroke: '#0d0e0d',
            color: '#0d0e0d'
          },
          label: {
            fontSize: 14,
            fontWeight: 400
          }
        },
        ports: {
          groups: this.groups,
          items: this.items
        }
      })

      this.stencil.load([start, end, rect, circle, prismatic])
    },
    initEvent() {
      // 鼠标移入
      this.graph.on('node:mouseenter',
        FunctionExt.debounce(() => {
          const container = document.getElementById('x6')
          const ports = container.querySelectorAll('.x6-port-body')
          this.showPorts(ports, true)
        }),
        500
      )
      this.graph.on('node:mouseleave', () => {
        const container = document.getElementById('x6')
        const ports = container.querySelectorAll('.x6-port-body')
        this.showPorts(ports, false)
      })
      this.graph.on('cell:contextmenu', ({ cell, e }) => {
        console.log(cell.getBBox().center)
        console.log(this.graph.localToGraph(cell.getBBox().center))
        cell.addTools([
          {
            name: cell.isEdge() ? 'edge-editor' : 'node-editor',
            args: {
              event: e
            }
          }
        ])
      })
    },
    initKeyboard() {
      const { graph } = this
      graph.bindKey(['meta+c', 'ctrl+c'], () => {
        const cells = graph.getSelectedCells()
        if (cells.length) {
          graph.copy(cells)
        }
        return false
      })
      graph.bindKey(['meta+x', 'ctrl+x'], () => {
        const cells = graph.getSelectedCells()
        if (cells.length) {
          graph.cut(cells)
        }
        return false
      })
      graph.bindKey(['meta+v', 'ctrl+v'], () => {
        if (!graph.isClipboardEmpty()) {
          const cells = graph.paste({ offset: 32 })
          graph.cleanSelection()
          graph.select(cells)
        }
        return false
      })
      graph.bindKey(['meta+z', 'ctrl+z'], () => {
        if (graph.history.canUndo()) {
          graph.history.undo()
        }
        return false
      })
      graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
        if (graph.history.canRedo()) {
          graph.history.redo()
        }
        return false
      })
      graph.bindKey(['meta+a', 'ctrl+a'], () => {
        const nodes = graph.getNodes()
        if (nodes) {
          graph.select(nodes)
        }
      })
      graph.bindKey('delete', () => {
        const cells = graph.getSelectedCells()
        if (cells.length) {
          graph.removeCells(cells)
        }
      })
      graph.bindKey(['ctrl+1', 'meta+1'], () => {
        const zoom = graph.zoom()
        if (zoom < 1.5) {
          graph.zoom(0.1)
        }
      })
      graph.bindKey(['ctrl+2', 'meta+2'], () => {
        const zoom = graph.zoom()
        if (zoom > 0.5) {
          graph.zoom(-0.1)
        }
      })
    },
    showPorts(ports, show) {
      for (let i = 0, len = ports.length; i < len; i = i + 1) {
        ports[i].style.visibility = show ? 'visible' : 'hidden'
      }
    }
  },
  mounted() {
    this.initX6()
  }
}
</script>

<style scoped>
.content {
  width: 100%;
  height: 100%;
  /*font-family: sans-serif;*/
  display: flex;
}

.app-stencil {
  width: 20%;
  border: 1px solid #f0f0f0;
  position: relative;
}

.app-content {
  flex: 1;
  height: 100%;
  margin-left: 8px;
  margin-right: -5px;
  box-shadow: 0 0 10px 1px #e9e9e9;
}
.el-header {
  background-color: #B3C0D1;
  color: #333;
  text-align: left;
}

.el-aside {
  background-color: #D3DCE6;
  color: #333;
  text-align: center;
}

.el-main {
  /*background-color: #E9EEF3;*/
  /*color: #333;*/
  text-align: center;
  /*line-height: 160px;*/
}

.el-container {
  height: 100%;
}
</style>
